// import com.alibaba.druid.sql.ast.SQLExpr;
// import com.alibaba.druid.sql.ast.SQLExprImpl;
// import com.alibaba.druid.sql.ast.SQLObject;
// import com.alibaba.druid.sql.ast.SQLReplaceable;
// import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor;
// import com.alibaba.druid.sql.visitor.SQLASTVisitor;

// import java.util.ArrayList;
// import java.util.List;

#include "OracleIsOfTypeExpr.h"
#include "../../../../ast/SQLExpr.h"
#include "../../../../ast/SQLObject.h"
#include "../../visitor/OracleASTVisitor.h"
#include "../../../../visitor/SQLASTVisitor.h"
#include "../../../../../utils/ifeq.h"
#include "../../../../../utils/listTran.h"
#include "../../../../../utils/listAddAll.h"

OracleIsOfTypeExpr::OracleIsOfTypeExpr()
{
  types = std::make_shared<std::list<SQLExpr_ptr>>();
}
// @Override
bool OracleIsOfTypeExpr::equals(Object_ptr o)
{
  if (this == o.get())
  {
    return true;
  }
  if (o == nullptr || getClass()->c_str() != o->getClass()->c_str())
  {
    return false;
  }

  OracleIsOfTypeExpr_ptr that = std::dynamic_pointer_cast<OracleIsOfTypeExpr>(o);

  if (expr != nullptr ? !expr->equals(that->expr) : that->expr != nullptr)
  {
    return false;
  }
  return types != nullptr ? IFEQ::ifeq<SQLExpr_ptr>(types, that->types) : that->types == nullptr;
}

// @Override
int OracleIsOfTypeExpr::hashCode()
{
  int result = expr != nullptr ? expr->hashCode() : 0;
  result = 31 * result + (types != nullptr ? typeid(*types).hash_code() /*types.hashCode()*/ : 0);
  return result;
}

// @Override
void OracleIsOfTypeExpr::accept0(SQLASTVisitor_ptr visitor)
{
  accept0(std::dynamic_pointer_cast<OracleASTVisitor>(visitor));
}

// @Override
void OracleIsOfTypeExpr::accept0(OracleASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(OracleIsOfTypeExpr)))
  {
    acceptChild(visitor, expr);
    SQLObject_list_ptr tmp1 = ListTran::tran_class<SQLExpr, SQLObject>(types);
    acceptChild(visitor, tmp1);
  }
  visitor->endVisit(SharedObject(OracleIsOfTypeExpr));
}

// @Override
BOOL_ptr OracleIsOfTypeExpr::replace(SQLExpr_ptr expr, SQLExpr_ptr target)
{
  if (this->expr == expr)
  {
    setExpr(target);
    return BOOL::TRUE;
  }

  auto it_types = types->begin();
  for (int i = 0; i < types->size(); i++)
  {
    std::advance(it_types, i);
    if (*it_types == expr)
    {
      target->setParent(SharedObject(OracleIsOfTypeExpr));
      *it_types = target;
      return BOOL::TRUE;
    }
  }

  return BOOL::FALSE;
}

// @Override
SQLObject_ptr OracleIsOfTypeExpr::clone()
{
  SQLObject_ptr clone_tmp = std::shared_ptr<OracleIsOfTypeExpr>(new OracleIsOfTypeExpr());
  std::shared_ptr<OracleIsOfTypeExpr> x = std::dynamic_pointer_cast<OracleIsOfTypeExpr>(clone_tmp);
  // OracleIsOfTypeExpr x = new OracleIsOfTypeExpr();
  if (expr != nullptr)
  {
    x->setExpr(expr);
  }
  return nullptr;
}

// @Override
SQLObject_list_ptr OracleIsOfTypeExpr::getChildren()
{
  SQLObject_list_ptr children = std::make_shared<std::list<SQLObject_ptr>>();
  if (expr != nullptr)
  {
    children->push_back(expr);
  }
  // children.addAll(types);
  Utils::ListAddAll<SQLExpr, SQLObject>(types, children);
  return children;
}

SQLExpr_ptr OracleIsOfTypeExpr::getExpr()
{
  return expr;
}

void OracleIsOfTypeExpr::setExpr(SQLExpr_ptr expr)
{
  if (expr != nullptr)
  {
    expr->setParent(SharedObject(OracleIsOfTypeExpr));
  }
  this->expr = expr;
}

SQLExpr_list_ptr OracleIsOfTypeExpr::getTypes()
{
  return types;
}
